/**
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License. 
 */
import { defineComponent, ref, SetupContext, watch } from "vue";
import { useCompare } from "../../composition/use-compare";
import { KeyCode, useEvent } from "../../composition/use-event";
import { DateObject, Period } from "../../types/common";
import { MonthViewItem } from "../../types/month";
import { MonthProps, monthProps } from "./month.props";

export default defineComponent({
    name: 'FDatePickerMonthView',
    props: monthProps,
    emits: ['click', 'keyDown', 'mouseEnter', 'mouseLeave'] as (string[] & ThisType<void>) | undefined,
    setup(props: MonthProps, context: SetupContext) {
        const months = ref<MonthViewItem[][]>(props.months);
        const enableMarkCurrent = ref(props.enableMarkCurrent);
        const enableKeyboadNavigate = ref(props.enableKeyboadNavigate);
        const enablePeriod = ref(props.enablePeriod);
        const selectedMonth = ref<DateObject | null>(props.selected);
        const selectedMonthPeriod = ref<Period | null>(props.selectedPeriod);
        const { equal, inPeriod, isInitializedDate, equalOrEarlier } = useCompare();
        const { getKeyCodeFromEvent } = useEvent();

        watch(() => props.months, () => {
            months.value = props.months;
        });
        watch(() => props.selected, () => {
            selectedMonth.value = props.selected;
        });

        function onClick($event: Event, target: MonthViewItem) {
            $event.stopPropagation();

            if (target.disable) {
                return;
            }
            context.emit('click', target);
        }

        function onKeyDown($event: KeyboardEvent, target: MonthViewItem) {
            const keyCode: number = getKeyCodeFromEvent($event);
            if (keyCode !== KeyCode.tab) {
                $event.preventDefault();

                if (keyCode === KeyCode.enter || keyCode === KeyCode.space) {
                    onClick($event, target);
                } else if (enableKeyboadNavigate.value) {
                    context.emit('keyDown', target);
                }
            }
        }

        function onMouseEnter(target: MonthViewItem) {
            if (selectedMonthPeriod.value &&
                isInitializedDate(selectedMonthPeriod.value.from) &&
                !isInitializedDate(selectedMonthPeriod.value.to)
            ) {
                months.value.forEach((row: MonthViewItem[]) => {
                    row.forEach((item: MonthViewItem) => {
                        item.range = !!selectedMonthPeriod.value &&
                            (
                                (equalOrEarlier(selectedMonthPeriod.value.from, item.date) && equalOrEarlier(item.date, target.date)) ||
                                (equalOrEarlier(item.date, selectedMonthPeriod.value.from) && equalOrEarlier(target.date, item.date))
                            );
                    });
                });
                context.emit('mouseEnter', target);
            }
        }

        function onMouseLeave() {
            months.value.forEach((row: MonthViewItem[]) => {
                row.forEach((item: MonthViewItem) => {
                    item.range = false;
                });
            });
            context.emit('mouseLeave');
        }

        function isMonthSame(monthDate: DateObject): boolean {
            return !!selectedMonth.value && equal(
                { year: selectedMonth.value.year, month: selectedMonth.value.month },
                { year: monthDate.year, month: monthDate.month }
            );
        }

        function isMonthRangeBeginOrEndSame(month: DateObject) {
            return !!selectedMonthPeriod.value && (
                equal({ year: selectedMonthPeriod.value.from.month }, month) ||
                equal({ year: selectedMonthPeriod.value.to.month }, month)
            );
        }

        function isMonthInPeriod(month: DateObject) {
            return inPeriod(month, selectedMonthPeriod.value);
        }

        const monthClass = (monthViewItem: MonthViewItem) => {
            const classObject = {
                'f-datepicker-month-cell': true,
                'f-datepicker-current': monthViewItem.isCurrent && enableMarkCurrent,
                'f-datepicker-selected': (!enablePeriod.value && isMonthSame(monthViewItem.date)) ||
                    (enablePeriod.value && isMonthRangeBeginOrEndSame(monthViewItem.date)),
                'f-datepicker-disabled': monthViewItem.disable,
                'f-datepicker-range': isMonthInPeriod(monthViewItem.date) || monthViewItem.range
            } as Record<string, boolean>;
            return classObject;
        };

        return () => {
            return (
                <div class="f-datepicker-table-wrapper">
                    <table class="f-datepicker-table">
                        <tbody>
                            {
                                months.value && months.value.map((row: MonthViewItem[], rowIndex: number) => {
                                    return (
                                        <tr>
                                            {
                                                row.map((monthViewItem: MonthViewItem, index: number) => {
                                                    return (
                                                        <td id={`m_${rowIndex}_${index}`} class={`m_${rowIndex}_${index}`}
                                                            onClick={(payload: MouseEvent) => onClick(payload, monthViewItem)}
                                                            onKeydown={(payload: KeyboardEvent) => onKeyDown(payload, monthViewItem)}
                                                            onMouseenter={() => onMouseEnter(monthViewItem)}
                                                            onMouseleave={() => onMouseLeave()} tabindex="0" style="width: 33.3%">
                                                            <div class="f-datepicker-month">
                                                                <span class={monthClass(monthViewItem)}>{monthViewItem.displayText}</span>
                                                            </div>
                                                        </td>
                                                    );
                                                })
                                            }
                                        </tr>
                                    );
                                })
                            }
                        </tbody>
                    </table>
                </div>
            );
        };
    }
});
